package tde_servicer

import (
	"log"
	"net"
	"os"
	"regexp"
	"strconv"
)

//type Message chan string
var logger *log.Logger
var maxSessions int = 72 //default 72
var maxLoginFailRestriction int
var tokenSeq int = 0

type Token chan int
type SessionTable map[string]*Session
type Tde_Server struct {
	listener net.Listener
	Sessions SessionTable
	// db       DB_service
	tokens   Token
	pending  chan net.Conn
	quiting  chan string
	incoming chan string
	outgoing chan string
	// quitAnnouncement chan bool // close this chan when server exit
}

func getenv(key, fallback string) string {
	value := os.Getenv(key)
	if len(value) == 0 {
		return fallback
	}
	return value
}

func init() {

	maxSess := os.Getenv("MAXDEVS")

	if len(maxSess) > 0 {
		max, err := strconv.Atoi(maxSess)
		if err == nil && max > 25 { //minum value 25
			maxSessions = max // default value , always have a value be set to the variable maxSessions
		}
	}

	// maxLoginF := os.Getenv("MAXLOGINFAILURE") //, "7")

	// logger.Printf("maxLoginF:%v\n", maxLoginF)
	// maxLoginFailRestriction, err := strconv.Atoi(maxLoginF)
	// logger.Printf("maxLoginFailRestriction:%v, err: %v \n", maxLoginFailRestriction, err)
	// if err != nil {
	// 	maxLoginFailRestriction = 7
	// 	logger.Printf("Please check Os parameter MAXLOGINFAILURE:%v , error: %v \nUse Default max login failure:%v\n", maxLoginF, err, maxLoginFailRestriction)
	// }

	maxLoginFailRestriction = 10

	logger = log.New(os.Stdout, "TDE SVR>", log.LstdFlags|log.Lshortfile)

}

func convertString2Float64(d []string) ([]float64, string) {
	var r [10]float64
	var i int = 0
	var msg, m string

	logger.Printf("converting, source: %v \n", d)

	for i, m = range d {

		logger.Printf("i:%v, m:%v\n", i, m)
		if v, e := strconv.ParseFloat(m, 64); e == nil && m != "" {
			r[i] = v
		} else {
			msg = `{ "flag":-1,"message":"Wrong data, non-numberic string."}`
			break
		}
	}
	i++
	logger.Printf("Converted, to: %v; msg: %v.\n", r[0:i], msg)
	return r[0:i], msg

}

func convertString2Int64(d []string) ([]int64, string) {
	var r [10]int64
	var i int = 0
	var msg, m string

	logger.Printf("converting, source: %v \n", d)

	for i, m = range d {

		logger.Printf("i:%v, m:%v\n", i, m)
		if v, e := strconv.ParseInt(m, 10, 64); e == nil && m != "" {
			r[i] = v
		} else {
			msg = `{ "flag":-1,"message":"Wrong data, non-numberic string."}`
			break
		}
	}
	i++
	logger.Printf("Converted, to: %v; msg: %v.\n", r[0:i], msg)
	return r[0:i], msg

}

func validDateFormat(d string) bool {
	logger.Printf("d='%v'\n", d)
	if regexp.MustCompile(`^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$`).MatchString(d) {

		return true
	} else {
		return false
	}

}
func validDateTimeFormat(d string) bool {
	logger.Printf("d='%v'\n", d)
	if regexp.MustCompile(`^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01]) (0[0-9]|1[0-9]|2[0-3]):[0-5]{0,1}[0-9]:[0-5]{0,1}[0-9]$`).MatchString(d) {

		return true
	} else {
		return false
	}

}

/*
func (self *Tde_Server) listen() {

	go func() {
		for {
			select {
			// case msg := <-self.incoming:
			// 	self.process(msg)
			case conn := <-self.pending:
				self.join(conn)
			case session_id := <-self.quiting:
				logger.Printf("*Tde_Server.listen: Sessions[%v] <- self.quiting.... \n", session_id)
				self.leave(session_id)

			}

		}

	}()
}

func (self *Tde_Server) join(conn net.Conn) {

	session, msg := CreateSession(conn, self)
	if session == nil {
		logger.Printf("No session created.\n")
		return
	}
	device_id := session.GetDevice_ID()

	self.Sessions[device_id] = session
	logger.Printf("Device [%v] connected to server.", device_id)

	go func() {

		for {

			message, ok := <-session.incoming
			if ok {
				msg := regexp.MustCompile(";").Split(message, -1)

				logger.Printf("[%v]>>[%v]:%v;%v;\n", device_id, msg[1], msg[2], msg[3])
				switch msg[0] {
				case "#":

					session.db <- DevMsg{msg[2], msg[3]}

				case "@":
					bridge := self.Sessions[msg[1]]
					if bridge != nil {

						bridge.db <- DevMsg{msg[2], msg[3]}

					} else {
						logger.Printf("Device [%v] is not active.\n", msg[1])
					}
				}

			}
			conn.SetReadDeadline(time.Now().Add(60 * 3.1 * time.Second))

		}
		logger.Printf("Session[%v] Time out ....\n", session_id)
		session.quit()
	}()

	go func() {
		for {
			session_id := <-session.quiting
			logger.Printf("Session [%v] is quiting \n", session_id)
			self.quiting <- session_id

		}

	}()

	session.incoming <- msg
}

func (self *Tde_Server) leave(device_id string) {
	logger.Printf("*Tde_Server.leave...... parameter: device_id=[%v]\n", device_id)
	if device_id != "" {
		d, ok := self.Sessions[device_id]
		if ok {
			d.close()
			delete(self.Sessions, device_id)
			self.generateToken()
			logger.Printf(" Device [%v] closed.\n", device_id)

		}
	}
	logger.Printf(" Device [%v] left.\n", device_id)

}

func CreateTdeServer() *Tde_Server {
	server := &Tde_Server{
		Sessions: make(DeviceTable, maxSessions),
		tokens:   make(Token, maxSessions),
		pending:  make(chan net.Conn),

		quiting:  make(chan string),
		incoming: make(chan string),
		outgoing: make(chan string),

		// quitAnnouncement: make(chan bool),
	}

	server.listen()
	return server
}

func (self *Tde_Server) Start(connString string) {

	tcpAddr, err := net.ResolveTCPAddr("tcp4", connString)
	checkError(err)

	self.listener, _ = net.ListenTCP("tcp", tcpAddr)
	logger.Printf("Tde Server %p starts at %s \n", self, tcpAddr)

	for i := 0; i < maxSessions; i++ {
		self.generateToken()
	}
	logger.Printf("Generated Token #:%v\n", tokenSeq)

	for {

		conn, err := self.listener.Accept()
		if err != nil {
			logger.Printf("Error at Tde_Server.Start Accept():%v\n", err)

			continue
		}

		logger.Printf("A new device [%v] kicks \n", conn)

		self.takeToken()
		self.pending <- conn

	}

}

func (self *Tde_Server) generateToken() {
	self.tokens <- tokenSeq
	tokenSeq++
	// logger.Printf("Generated Token #:%v\n", tokenSeq)
}

func (self *Tcp_Server) takeToken() {
	t := <-self.tokens
	logger.Printf("Taken Token #:%v\n", t)
}

func checkError(err error) {
	if err != nil {
		logger.Printf("Fatal error: %s\n", err.Error())
		os.Exit(1)
	}
}

*/
